#include "stdafx.h"
#include "xThread.h"

#define WM_ASYNC_MSG	(WM_USER + 0x1000)
#define WM_ASYNCRET_MSG	(WM_USER + 0x2000)

AsyncParam::AsyncParam(WPARAM wParam, LPARAM lParam, FnAsync then, DWORD ret, WPARAM wParamSrc, LPARAM lParamSrc)
{
	_wParam = wParam;
	_lParam = lParam;
	_then = then;
	_ret = ret;
	_wParamSrc = wParamSrc;
	_lParamSrc = lParamSrc;
}

xThread::xThread()
{
	m_hThread = NULL;
	m_dwThreadID = 0;
}

xThread::~xThread()
{
	Destroy();
}

DWORD WINAPI xThread::ThreadProc(LPVOID lpParam)
{
	ThreadProcParam	*pParam = (ThreadProcParam*)lpParam;

	if(pParam == NULL)
	{
		return 0x1234;
	}

	xThread		*pThread = (xThread*)pParam->_lParam;

	if(pThread != NULL)
	{
		pThread->OnThreadProc(pParam->_wParam, lpParam);
	}

	delete pParam;

	return 0x112;
}

void xThread::OnThreadProc(DWORD wParam, LPVOID lpParam)
{
	MSG	msg;

	while(TRUE)
	{
		if(OnMessageLoop(msg))
		{
			break;
		}
	}
}

DWORD xThread::CreateThread(WPARAM wParam)
{
	//if(m_hThread != 0)
	//{
	//	assert(FALSE);
	//	return 0;
	//}

	ThreadProcParam	*pParam = new ThreadProcParam;

	pParam->_wParam = wParam;
	pParam->_lParam = (WPARAM)this;

	m_hThread = ::CreateThread(NULL, NULL, ThreadProc, pParam, 0, &m_dwThreadID);

	return m_dwThreadID;
}

void xThread::Destroy(BOOL bSync)
{
	if(m_dwThreadID != 0)
	{
		PostThreadMessage(m_dwThreadID, WM_QUIT, 0, 0);
		if(bSync)
		{
			WaitForSingleObject(m_hThread, INFINITE);
		}
		CloseHandle(m_hThread);
		m_dwThreadID = 0;
		m_hThread = NULL;
	}
}

BOOL xThread::PreTranslateMessage(MSG &msg)
{
	if(msg.message >= WM_ASYNC_MSG && msg.message <= WM_ASYNC_MSG + 0x1000)
	{
		AsyncParam	*pAsync = (AsyncParam*)msg.wParam;

		if(pAsync != NULL)
		{
			OnAsyncMsg(msg.message - WM_ASYNC_MSG, pAsync->_wParam, pAsync->_lParam, pAsync->_ret, pAsync->_then);
			delete pAsync;
		}
	}
	else if(msg.message >= WM_ASYNCRET_MSG && msg.message <= WM_ASYNCRET_MSG + 0x1000)
	{
		AsyncParam	*pAsync = (AsyncParam*)msg.wParam;

		if(pAsync != NULL)
		{
			if(pAsync->_then != NULL)
			{
				pAsync->_then(pAsync->_wParam, pAsync->_lParam, pAsync->_wParamSrc, pAsync->_lParamSrc);
			}
			delete pAsync;
		}
	}
	else if(msg.message == WM_DESTROYFRAMERETURN)
	{
		AsyncParam	*pAsync = (AsyncParam*)msg.wParam;

		if(pAsync != NULL)
		{
			if(pAsync->_then != NULL)
			{
				pAsync->_then(pAsync->_wParam, pAsync->_lParam, pAsync->_wParamSrc, pAsync->_lParamSrc);
			}
			delete pAsync;
		}
	}
	return FALSE;
}

void xThread::OnAsyncMsg(DWORD dwFuncID, WPARAM wParam, LPARAM lParam, DWORD nThreadIDReturn, FnAsync then)
{
}

BOOL xThread::OnMessageLoop(MSG &msg)
{
	if(!PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE))
	{
		GetMessage(&msg, NULL, 0, 0);
	}

	PreTranslateMessage(msg);

	return msg.message == WM_QUIT;
}

void xThread::Attach(DWORD dwThreadID)
{
	m_dwThreadID = dwThreadID;
}

void xThread::Detach()
{
	m_dwThreadID = 0;
}

AsyncParam *Async(DWORD nThreadID, DWORD nFuncID, WPARAM wParam, LPARAM lParam, DWORD nThreadIDReturn)
{
	AsyncParam	*pAsync = new AsyncParam(wParam, lParam, NULL, nThreadIDReturn);

	PostThreadMessage(nThreadID, WM_ASYNC_MSG + nFuncID, (WPARAM)pAsync, 0);

	return pAsync;
}

void AsyncReturn(DWORD nThreadID, FnAsync then, DWORD nFuncID, WPARAM wParam, LPARAM lParam, WPARAM wParamSrc, LPARAM lParamSrc)
{
	AsyncParam	*pAsync = new AsyncParam(wParam, lParam, then, 0, wParamSrc, lParamSrc);

	PostThreadMessage(nThreadID, WM_ASYNCRET_MSG + nFuncID, (WPARAM)pAsync, 0);
}